namespace BingMaps.ViewModel
{
    using System;
    using System.Device.Location;
    using System.Globalization;
    using System.Reactive.Linq;
    using System.Windows;
    using GalaSoft.MvvmLight.Command;
    using GalaSoft.MvvmLight.Messaging;
    using GalaSoft.MvvmLight.Threading;
    using Microsoft.Phone.Controls.Maps;
    using WP7Contrib.Logging;
    using WP7Contrib.Services.BingMaps;
    using WP7Contrib.Services.BingMaps.Model;
    using WP7Contrib.Services.Location;
    using WP7Contrib.Services.Navigation;
    using WP7Contrib.Services.Storage;

    public class SearchAreaViewModel : ViewModelBaseWp7
    {
        #region Constants and Fields

        private readonly IBingMapsService bingMapsService;

        private readonly ILocationService locationService;

        private LocationRect boundingRectangle;

        private GeoCoordinate currentDeviceGeoCoordinate;

        private IDisposable currentLocationObserver;

        private GeoCoordinate currentMapSearchCenterPoint;

        private string searchQuery;

        private RelayCommand selectSearchCommand;

        private double zoomLevel;

        private SearchResult searchResult;

        #endregion

        #region Constructors and Destructors

        public SearchAreaViewModel(
            INavigationService navigationService, 
            IMessenger messenger, 
            ILocationService locationService, 
            IBingMapsService bingMapsService,
            ILog log)
            : base(navigationService, messenger, log)
        {
            this.locationService = locationService;
            this.bingMapsService = bingMapsService;

            DispatcherHelper.CheckBeginInvokeOnUI(() => { this.ZoomLevel = 16; });

            this.ExecuteSelectFindMyCurrentLocationCommand();
        }

        #endregion

        #region Properties

        public LocationRect BoundingRectangle
        {
            get
            {
                return this.boundingRectangle;
            }

            set
            {
                this.SetPropertyAndNotify(ref this.boundingRectangle, value, "BoundingRectangle");
            }
        }

        public GeoCoordinate CurrentDeviceGeoCoordinate
        {
            get
            {
                return this.currentDeviceGeoCoordinate;
            }

            set
            {
                this.SetPropertyAndNotify(ref this.currentDeviceGeoCoordinate, value, "CurrentDeviceGeoCoordinate");
            }
        }

        public GeoCoordinate CurrentMapSearchCenterPoint
        {
            get
            {
                return this.currentMapSearchCenterPoint;
            }

            set
            {
                this.SetPropertyAndNotify(ref this.currentMapSearchCenterPoint, value, "CurrentMapSearchCenterPoint");
            }
        }

        public string SearchQuery
        {
            get
            {
                return this.searchQuery;
            }

            set
            {
                this.SetPropertyAndNotify(ref this.searchQuery, value, "SearchQuery");
            }
        }

        public RelayCommand SelectBingSearchCommand
        {
            get
            {
                return this.selectSearchCommand ??
                       (this.selectSearchCommand =
                        new RelayCommand(this.ExecuteBingSearchCommand));
            }
        }

        public double ZoomLevel
        {
            get
            {
                return this.zoomLevel;
            }

            set
            {
                this.SetPropertyAndNotify(ref this.zoomLevel, value, "ZoomLevel");
            }
        }

        #endregion

        #region Methods

        private void ExecuteSelectFindMyCurrentLocationCommand()
        {
            this.currentLocationObserver =
                this.locationService.Location().ObserveOnDispatcher().Subscribe(
                    geoCoordinate =>
                    {
                        this.CurrentDeviceGeoCoordinate = geoCoordinate;
                        this.CurrentMapSearchCenterPoint = this.CurrentDeviceGeoCoordinate;
                    });
        }

        protected override void IsBeingActivated(IStorage storage)
        {
        }

        protected override void IsBeingDeactivated(IStorage storage)
        {
        }

        public override void Cleanup()
        {
            if (this.currentLocationObserver != null)
            {
                this.currentLocationObserver.Dispose();
                this.currentLocationObserver = null;
            }

            base.Cleanup();
        }

private void ExecuteBingSearchCommand()
{
    try
    {
        this.SearchResult = null;
        var criterion = CriterionFactory.CreateSearchForServices(new LocationRect(this.CurrentDeviceGeoCoordinate, 5, 5),
                                                                    this.SearchQuery,
                                                                    CultureInfo.CurrentCulture);

        this.bingMapsService.SearchForServices(criterion)
            .ObserveOnDispatcher()
            .Subscribe(this.ProcessBingSearchResponse, FailedSearch, CompletedSearch);
    }
    catch (Exception exn)
    {
        MessageBox.Show(string.Format("Failed! Message - '{0}", exn.Message), "Services Search", MessageBoxButton.OK);
    }
}

private void ProcessBingSearchResponse(SearchResult result)
{
    if (result == null)
    {
        return;
    }

    this.SearchResult = result;
}

        public SearchResult SearchResult
        {
            get
            {
                return this.searchResult;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.searchResult, value, "SearchResult");
            }
        }

        private static void FailedSearch(Exception exn)
        {
            MessageBox.Show(string.Format("Failed! Message - '{0}", exn.Message),
                                         "Services Search",
                                         MessageBoxButton.OK);
        }

        private static void CompletedSearch()
        {
        }

        #endregion
    }
}